<?php
/** Yz_User_Basic: the class for current user (the client) management
 *
 *  the user class does not operate with the complete user model which may vary.
 *  The properties required by this class are:
 *  - user id
 *  - login (which can be the email address in some models)
 *  - password (in different models, it can also vary)
 *  - last login time
 *  - last login IP
 *  In case the complete user information is required, a different model is to be queried.
 */
class Yz_User_Default
    extends Yz_Object
    implements Yz_User_Interface
{

    protected $session;
    protected $userObject;
    protected $userModel;
    /**
    * User ID
    *
    * @var string
    */
    protected $id;

    /**
    * @var static
    */
    protected static $instance;

        /**
    * getInstance() : provides Singleton pattern
    *
    */
    public static function getInstance()
    {
        debug();

        $inst =& static::$instance;
        if ( null === $inst )
            $inst = new static;
        return $inst;
    }


    protected function __construct()
    {
        debug();
        $this->session = Yz_Session_Default::getInstance();
        // TODO verify user id && get info: probably not here but JIT
        $id = $this->session->getUserId();
        if ($id > 0) {
            $this->userObject = $this->fetchUserById($id);
            $this->id = $this->userObject->id;
        }
    }

    public function __destruct()
    {
    } // __destruct


    /** authenticate():
    */
    public function authenticate( $login, $password )
    {
        debug("Login: '$login', password: '$password'");
        if ($this->id > 0)
            throw new Yz_Access_Exception_Forbidden();
        $user = $this->fetchUserByLogin($login);
        $user->verifyPassword($password);
        $this->userObject = $user;
        $this->id = $this->userObject->id;
        $this->session->updateUserId($this);
        $this->updateLoginInfo();
        return $this;
    } // authenticate

    /** logout and remove all user info from $this
     *  @return chainable
     */
    public function logout()
    {
        debug();
        $this->id = 0;
        $this->userObject = null;
        $this->session->updateUserId($this);
        return $this;
    } // logout


    /** getter for $this.id
     *  @return int
     */
    public function getId()
    {
        debug();
        return $this->id;
    } // getId

    /** getter for $this.login
     *  @return string|null
     */
    public function getLogin()
    {
        if (null === $this->userObject)
            return null;
        return $this->userObject->login;
    } // getLogin

    /** isAdmin():
     * TODO use roles
     */
    public function isAdmin()
    {
        debug();
        return $this->id > 0;
    } // isAdmin

    /** test whether a user is authenticated
     *
     * Effectively, this means that a user id has been assigned
     *
     *  @return bool
     */
    public function isAuthenticated()
    {
        debug();
        return $this->id > 0;
    } // isAuthenticated

    /** getUserInfo(): return the user's data object (Model)
     *
     *  Intended to provide access to the current user's complete information
     *      which is possibly contained in a different model than that used by $this internally
     *  @return Item_User|null
     */
    public function getUserInfo()
    {
        return $this->userObject;
    } // getUserInfo


    protected function fetchUserById($id)
    {
        debug();
        $model = $this->selectUserModel();
        $item = $model->fetchItemById($id);
        return $item;
    }

    protected function fetchUserByLogin($login)
    {
        debug();
        $model = $this->selectUserModel();
        $item = $model->fetchUserByLogin($login);
        return $item;
    }


    protected function updateLoginInfo()
    {
        debug();
        $user = $this->userObject;
        $user->lastLoginIP = Yz_HTTP_Request::getInstance()->getRemoteAddr();
        $user->lastLoginTime = (int)YZ_TIME;
        $user->save();
        #$model = $this->selectUserModel();
        #$model->updateUserLoginTime($user);
        return $this;
    }

    protected function selectUserModel()
    {
        $m =& $this->userModel;
        if (null === $m) {
            $module = Yz::selectModule("Users");
            $m = $module->selectModel();
        }
        return $m;
    }

} // class
